#
# peerscape.replication.relate
#
# Copyright 2008 Helsinki Institute for Information Technology
# and the authors.
#
# Authors: Ken Rimey <rimey@hiit.fi>
#

# Permission is hereby granted, free of charge, to any person
# obtaining a copy of this software and associated documentation files
# (the "Software"), to deal in the Software without restriction,
# including without limitation the rights to use, copy, modify, merge,
# publish, distribute, sublicense, and/or sell copies of the Software,
# and to permit persons to whom the Software is furnished to do so,
# subject to the following conditions:
#
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
# CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

from __future__ import with_statement

def list_desired_datasets(db, person):
    with db.read_transaction():
        return (list_related_people(db, person)
                | list_desired_content(db, person))

def list_related_people(db, person):
    with db.read_transaction():
        return (set([person])
                | list_friends(db, person)
                | list_friends_of_friends(db, person)
                | list_fellow_members(db, person))

def list_desired_content(db, person):
    with db.read_transaction():
        return (list_links(db, person)
                | list_links_of_friends(db, person)
                | list_links_of_groups(db, person))

def list_friends(db, person):
    return set(db.list_friends(person))

def list_members(db, group):
    return set(db.list_members(group))

def list_memberships(db, person):
    with db.read_transaction():
        return set(group for group in db.list_datasets('group')
                   if person in db.members(group))

def list_links(db, person_or_group):
    return set(db.list_links(person_or_group, field='iid'))

def list_friends_of_friends(db, person):
    result = set()
    with db.read_transaction():
        friends = list_friends(db, person)
        for friend in friends:
            result |= list_friends(db, friend)

        result.discard(person)
        result -= friends
        return result

def list_fellow_members(db, person):
    result = set()
    with db.read_transaction():
        for group in list_memberships(db, person):
            result |= list_members(db, group)

        result.discard(person)
        return result

def list_links_of_friends(db, person):
    result = set()
    with db.read_transaction():
        for friend in list_friends(db, person):
            result |= list_links(db, friend)

        return result

def list_links_of_groups(db, person):
    result = set()
    with db.read_transaction():
        for group in list_memberships(db, person):
            result |= list_links(db, group)

        return result

if __name__ == '__main__':
    from peerscape import DB
    from peerscape.core.identity import generate

    def create_person(db):
        iid, master_secret = db.create_principal(_identity=generate(size=512))
        return iid, db.get_private_key(iid, master_secret)

    def fake_friendship(db, person1, person2):
        iid1, pk1 = person1
        iid2, pk2 = person2
        db.put(iid1, ['auth', iid2], {}, identity=pk1)
        db.put(iid2, ['auth', iid1], {}, identity=pk2)

    db = DB()
    p1 = db.init_persona(_identity=generate(size=512))
    person1 = p1, db.get_private_key()

    p2, _ = person2 = create_person(db)
    p3, _ = person3 = create_person(db)
    p4, _ = person4 = create_person(db)
    p5, _ = person5 = create_person(db)
    fake_friendship(db, person1, person2)
    fake_friendship(db, person1, person3)
    fake_friendship(db, person2, person3)
    fake_friendship(db, person2, person4)

    assert list_friends(db, p1) == set([p2, p3])
    assert list_friends_of_friends(db, p1) == set([p4])

    g = db.create_group()
    db.put(g, ['auth', p4], {})
    db.put(g, ['auth', p5], {})

    assert list_members(db, g) == set([p1, p4, p5])
    assert list_memberships(db, p1) == set([g])
    assert list_fellow_members(db, p1) == set([p4, p5])
    assert list_related_people(db, p1) == set([p1, p2, p3, p4, p5])

    c1 = db.create_dataset('My Content')
    c2 = db.create_dataset('Friend Content')
    c3 = db.create_dataset('Group Content')
    db.add_link(p1, c1)
    #db.add_link(p2, c2)
    db.add_link(g, c3)

    assert list_links(db, p1) == set([c1])
    assert list_links_of_friends(db, p1) == set()
    assert list_links_of_groups(db, p1) == set([c3])
    assert list_desired_content(db, p1) == set([c1, c3])

    assert list_desired_datasets(db, p1) == set([p1, p2, p3, p4, p5, c1, c3])
